package jdclib.structs;

import java.util.LinkedList;

/**
 * This class allows for an ordered collection of bytes to be created and modified without any preliminary knowledge of the total length.
 * Unlike the ByteBuffer class, no array exists until it is asked for. Thus, this structure is stand-alone, in that it does not simply wrap
 * or manage an external array referenced at the time of instantiation.
 * @author Davis Clark
 *
 */
public class ByteArrayBuilder
{
	protected LinkedList<Byte> Bytes;
	protected int Length = 0;
	
	public ByteArrayBuilder()
	{
		this.Bytes = new LinkedList<Byte>();
	}

	/**
	 * Adds a byte to the end of the collection.
	 * @param b		The byte to add.
	 */
	public void add(byte b)
	{
		this.Bytes.add(b);
		Length++;
	}
	
	/**
	 * Gets the value of the byte at a specific position with the collection. The byte is not removed from the underlying collection.
	 * @param index		Index of the desired byte.
	 * @return	The byte value at the specified position.
	 */
	public byte get(int index)
	{
		return Bytes.get(index);
	}
	
	/**
	 * Removes a byte from the underlying collection.
	 * @param index		The index of the byte to remove.
	 * @return	The removed byte.
	 */
	public byte remove(int index)
	{
		Length--;
		return Bytes.remove(index);
	}

	/**
	 * Gets an array representation of the current state of the ByteArrayBuilder. The underlying structure is not modified in any way.
	 * @return	The array representation.
	 */
	public byte[] getArray()
	{
		byte[] out = new byte[Length];
		for(int i = 0; i<Length; i++)
			out[i] = Bytes.get(i);
		
		return out;
	}
	
	public byte[] getOffsetArray(int offsetHead, int offsetTail)
	{
		byte[] out = new byte[Length-offsetTail-offsetHead];
		for(int i=offsetHead;i<Length-offsetTail;i++)
			out[i] = Bytes.get(i);
		return out;
	}
	
	/**
	 * Removes a byte from the end of the underlying collection.
	 * @return	The removed byte.
	 */
	public byte removeLast()
	{
		byte out = Bytes.removeLast();
		Length--;
		return out;
	}
	
	/**
	 * Removes a number of bytes from the end of the underlying collection.
	 * @param count	 The number of bytes to remove.
	 * @return	An array representation of the removed bytes.
	 */
	public byte[] removeLastBatch(int count)
	{
		byte[] popped = new byte[count];
		for(int i=0; i<count; i++)
			popped[i] = this.Bytes.removeLast();
		Length = Length - count;
		return popped;
	}
	
	/**
	 * Gets the number of bytes in the underlying collection. 
	 * @return The length
	 */
	public int length()
	{
		return Length;
	}

	/**
	 * Clears the underlying collection of bytes and returns its array representation.
	 * @return The array representaton of the ByteArrayBuilder.
	 */
	public byte[] clear()
	{
		byte[] temp = this.getArray();
		this.Bytes.clear();
		Length = 0;
		return temp;
	}
}

